﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;


public class DrawSetting
{
    public DrawSetting(float _moveSpeed = 100, float _newPointMaxDis = 20, float _maxProjectDis = 6, float _drawMaskDis = 1)
    {
        moveSpeed = _moveSpeed;
        //minDis = _minDis;
        newPointMaxDis = _newPointMaxDis;
        maxProjectDis = _maxProjectDis;
        drawMaskDis = _drawMaskDis;
    }

    public float moveSpeed = 100f;    // 画刷速度
    //public float minDis = 20.0f;    // 路劲索引是否增加的判断距离
    public float newPointMaxDis = 20;    // 新的点跟上一个点的最大间隔距离
    public float maxProjectDis = 6;    // 画的时候，左右最大偏移量
    public float drawMaskDis = 1f;    // 多长距离创建一个面片
}

public class DrawRealize2D : MonoSingleton<DrawRealize2D>
{


    private Transform m_Number;    // 数字UI的父对象
    private Transform m_Brush;    // 刷子
    private Transform m_DrawMask;    // 显示层
    private Transform m_AnimParent;    // 显示层

    private DrawSetting setting;

    private Image m_Sign;    // 跟随鼠标的标记点
    // 
    private Canvas m_Canvas;

    private System.Action completeCallback = null;    // 完成事件回调
    private System.Action eatAnimCallback = null;    // 触碰路径上的动物回调


    [SerializeField]
    private int m_WayPointIndex = 0;    // 当前路径索引
    [SerializeField]
    private int m_MovePointIndex = 0;    // 刷子移动的路径索引记录
    [SerializeField]
    private int m_DrawOrder = 0;    // 当前写的笔画步骤

    private bool bIsDrawing = false;    // 是否正在画
    private bool bIsHoving = false;
    private bool bIsLastPoint = false;
    private bool bIsFirstCreateMask;
    private bool bIsPause;

    private bool _IsBrushMoving;
    public bool IsBrushMoving
    {
        get { return _IsBrushMoving; }
    }

    // ui的材质球
    private Material m_NumberMaterial;

    private Vector3 m_CurrentPoint;    // 当前画刷要移动的位置
    private Vector3 m_MaskPreviousPoint;    // 遮罩记录画刷上次位置
    //private Vector3 m_BrushPreviousPoint;    // 画刷上次位置

    private Transform m_CurrentPointSign;    // 当前画刷要移动的位置


    [SerializeField]
    private Transform[] m_NumberArray;    // 数字笔画Image的一个数组

    [SerializeField]
    private Vector3[] m_WayPoints;    // 当前笔画的路径数组

    private List<Transform> m_Anims = new List<Transform>();    //当前路径上能吃的东西
    //private List<GameObject> m_EatAnims = new List<GameObject>();    //当前路径上已经吃掉的东西

    List<GameObject> m_MaskList = new List<GameObject>();
    List<GameObject> m_DrawList = new List<GameObject>();

    // 笔画的路径数组
    private Dictionary<int, Vector3[]> drawPathDict = new Dictionary<int, Vector3[]>();

    private const string downShader = "Custom/UnlitStencilDown";
    private const string upShader = "Custom/UnlitStencilUp";
    
    void Update()
    {
        _IsBrushMoving = false;

        if (!bIsDrawing || bIsPause)
            return;

        if (Input.GetMouseButtonDown(0))
            OnClickDown();
        if (Input.GetMouseButton(0))
            OnClickHover();
        if (Input.GetMouseButtonUp(0))
            OnClickUp();

        CheckBrushMove();
        CheckAnims();
        CheckDrawMask();
        m_Sign.transform.position = UGUITool.ScreenPointToUGUIPoint(m_Canvas, Input.mousePosition);
    }

    public void DrawNumber(Transform number, Transform brush, Transform mask, Image sign, Canvas canvas, Transform animParent, System.Action onDrawCompleteCallback = null, System.Action onEatAnimCallback = null, DrawSetting settingInfo = null)
    {
        Clear();

        m_Number = number;
        m_Brush = brush;
        m_DrawMask = mask;
        m_AnimParent = animParent;
        m_Sign = sign;
        m_Canvas = canvas;
        completeCallback = onDrawCompleteCallback;
        eatAnimCallback = onEatAnimCallback;
        if (settingInfo == null)
            setting = new DrawSetting();
        else
            setting = settingInfo;

        Initialize();
        StartDraw();
    }

    public void Pause()
    {
        bIsPause = true;
    }

    public void Resume()
    {
        bIsPause = false;
    }

    private void Initialize()
    {
        m_Number.gameObject.SetActive(true);
        m_Brush.gameObject.SetActive(true);
        m_Sign.gameObject.SetActive(false);
        //m_Sign.gameObject.SetActive(true);
        m_CurrentPointSign = GameObject.Instantiate(m_Sign.transform);
        m_CurrentPointSign.SetParent(m_Sign.transform.parent);
        m_CurrentPointSign.localScale = Vector3.one * 0.5f;
        m_CurrentPointSign.gameObject.SetActive(false);
        //m_CurrentPointSign.gameObject.SetActive(true);

        bIsFirstCreateMask = true;
        bIsDrawing = false;
        bIsHoving = false;
        bIsLastPoint = false;
        bIsPause = false;

        m_WayPointIndex = 0;
        m_MovePointIndex = 0;
        m_DrawOrder = 0;

        SetUpMaterial(m_DrawMask);

        DrawPathMono[] pathMonos = m_Number.GetComponentsInChildren<DrawPathMono>();
        for (int i = 0; i < pathMonos.Length; i++)
        {
            DrawPathMono mono = pathMonos[i];
            drawPathDict.Add(mono.pathID, mono.pathArray);
        }

        Transform Number_Order = m_Number.Find("Order");
        m_NumberArray = new Transform[Number_Order.childCount];
        for (int i = 0; i < Number_Order.childCount; i++)
        {
            m_NumberArray[i] = Number_Order.GetChild(i);
            //Debug.Log("index:" + i + "   Name:" + m_NumberArray[i].name);
        }
    }

    private void StartDraw()
    {
        if (m_NumberArray.Length <= 0)
        {
            Debug.LogError("数据错误！");
            return;
        }

        for (int i = 0; i < m_NumberArray.Length; i++)
        {
            Transform target = m_NumberArray[i];
            target.gameObject.SetActive(false);
            if (target.childCount> 0)
            {
                Transform hint = m_NumberArray[i].GetChild(0);
                if (hint != null)
                {
                    hint.gameObject.SetActive(false);
                }
            }
        }

        m_DrawOrder = 0;
        DrawNumberOrder(m_DrawOrder);
    }

    private void DrawNumberOrder(int orderIndex)
    {
        Transform target = m_NumberArray[orderIndex];

        bIsHoving = false;
        bIsDrawing = true;
        bIsLastPoint = false;
        m_WayPointIndex = 0;
        m_MovePointIndex = 0;
        target.gameObject.SetActive(true);
        Transform hint = target.childCount > 0 ? target.GetChild(0) : null;
        if (hint != null)
        {
            hint.gameObject.SetActive(true);
        }
        Transform animParent = target.childCount > 1 ? target.GetChild(1) : null;
        foreach (Transform t in m_Anims)
        {
            if (t != null) t.SetActive(false);
        }
        m_Anims.Clear();
        if (animParent != null)
        {
            for (int i = 0; i < animParent.childCount; i++)
            {
                m_Anims.Add(animParent.GetChild(i));
            }
            Debug.LogError("anima count:" + m_Anims.Count);
        }

        SetDrawMaterial(target);
        m_WayPoints = drawPathDict[orderIndex];

        m_Brush.position = m_CurrentPoint = m_MaskPreviousPoint = m_WayPoints[0];
        m_Brush.rotation = Quaternion.LookRotation((m_WayPoints[1] - m_WayPoints[0]).normalized, m_Brush.up);

        //float angle = Vector3.Angle((m_WayPoints[1] - m_WayPoints[0]).normalized, m_Brush.forward);
        //m_Brush.Rotate(new Vector3(0, angle, 0), Space.Self);


    }

    private void DrawComplete()
    {
        Debug.Log("全部画完！");
        bIsDrawing = false;
        if (completeCallback != null)
        {
            completeCallback();
        }
        Clear();
        DestroyInstance();
    }

    private void OnClickDown()
    {
        bIsHoving = true;
    }

    private void OnClickHover()
    {
        if (!bIsDrawing) return;
        //if (!bIsHoving) return;

        CheckNextMovePoint();
    }

    private void OnClickUp()
    {
        bIsHoving = false;
    }

    private void DrawNextOrder()
    {

        m_DrawOrder++;
        if (m_DrawOrder >= m_NumberArray.Length)
        {
            bIsDrawing = false;
            DrawComplete();
            return;
        }
        else
        {
            //Debug.Log("--------------: DrawNext");
            DrawNumberOrder(m_DrawOrder);
        }
    }

    private void DrawCurrentOrderEnd()
    {
        foreach (GameObject go in m_DrawList)
        {
            go.SetActive(false);
        }

        m_MaskList.AddRange(m_DrawList.ToArray());
        m_DrawList.Clear();

        Transform target = m_NumberArray[m_DrawOrder];
        SetDefaultMaterial(target);

        if (target.childCount > 0)
        {
            Transform hint = target.GetChild(0);
            if (hint != null)
            {
                hint.gameObject.SetActive(false);
            }
        }

        DrawNextOrder();
    }

    void CheckBrushMove()
    {
        if (!bIsDrawing)
            return;

        float speed = Vector3.Distance(m_Brush.position, m_CurrentPoint) > 10 ? setting.moveSpeed : setting.moveSpeed * Vector3.Distance(m_Brush.position, m_CurrentPoint) / 10;
        //m_BrushPreviousPoint = m_Brush.position;
        if (m_MovePointIndex < m_WayPointIndex)
        {
            //Vector3 startPoint = m_WayPoints[m_MovePointIndex];
            Vector3 movePoint = m_WayPoints[m_MovePointIndex + 1];
            Vector3 moveDir = movePoint - m_Brush.position;

            m_Brush.position += moveDir.normalized * Time.deltaTime * speed;
            m_Brush.rotation = Quaternion.LookRotation(moveDir.normalized, m_Brush.up);

            _IsBrushMoving = true;
            //m_Brush.rotation = Quaternion.LookRotation((movePoint - startPoint).normalized, m_Brush.up);
            //float angle = Vector3.Angle(moveDir.normalized, m_Brush.forward);
            //m_Brush.Rotate(new Vector3(0, angle, 0), Space.Self);
            float dis = Vector3.Distance(m_Brush.position, movePoint);
            if (dis < 3)
            {
                m_MovePointIndex++;
            }
        }
        else
        {
            //Vector3 startPoint = m_WayPoints[m_MovePointIndex - 1];
            //Vector3 endPoint = m_WayPoints[m_MovePointIndex];
            Vector3 movePoint = m_CurrentPoint;
            float dis = Vector3.Distance(m_Brush.position, movePoint);
            if (dis > 3)
            {
                Vector3 moveDir = movePoint - m_Brush.position;
                m_Brush.position += moveDir.normalized * Time.deltaTime * speed;
                m_Brush.rotation = Quaternion.LookRotation(moveDir.normalized, m_Brush.up);
                _IsBrushMoving = true;
                //m_Brush.rotation = Quaternion.LookRotation((endPoint - startPoint).normalized, m_Brush.up);
                //float angle = Vector3.Angle(moveDir.normalized, m_Brush.forward);
                //m_Brush.Rotate(new Vector3(0, angle, 0), Space.Self);
            }
            else
            {
                if (bIsLastPoint)
                {
                    DrawCurrentOrderEnd();
                }
            }
        }

    }

    // 检测路径上能吃的东西
    void CheckAnims()
    {
        if (m_Anims.Count > 0)
        {
            for (int i = 0; i < m_Anims.Count; i++)
            {
                Transform target = m_Anims[i];
                if (Vector3.Distance(target.position, m_Brush.position) < 4)
                {
                    target.GetComponent<DrawEatAnimMono>().PlayAnim();
                    target.SetParent(m_AnimParent);
                    m_Anims.RemoveAt(i);

                    //Debug.LogError("1111111111");
                    if (eatAnimCallback != null)
                    {
                        //Debug.LogError("22222222222");
                        eatAnimCallback();
                    }
                    i--;
                    //m_EatAnims.Add(target.gameObject);
                }
            }
        }
    }

    void CheckNextMovePoint()
    {
        if (bIsLastPoint)
            return;

        Vector3 signPosition = m_Sign.transform.position;
        Vector3 startPoint, endPoint;
        if (m_WayPointIndex < m_WayPoints.Length - 1)
        {
            startPoint = m_WayPoints[m_WayPointIndex];
            endPoint = m_WayPoints[m_WayPointIndex + 1];
        }
        else
        {
            startPoint = m_CurrentPoint;
            endPoint = m_WayPoints[m_WayPointIndex];

            // 到达最后一个点
            if (Vector3.Distance(startPoint, endPoint) < 1)
            {
                m_CurrentPointSign.position = m_CurrentPoint;
                bIsLastPoint = true;
                return;
            }
        }

        Debug.DrawLine(startPoint, endPoint);

        Vector3 moveDirection = endPoint - startPoint; // 移动方向向量
        Vector3 projectDirection = signPosition - startPoint; // 投射方向向量

        if (Vector3.Dot(moveDirection.normalized, projectDirection.normalized) < 0)
            return;
        Vector3 projectPoint = Vector3.Project(projectDirection, moveDirection.normalized) + startPoint; //投射点
        float projectDis = Vector3.Distance(projectPoint, signPosition);
        //Debug.Log("左右距离：" + projectDis);
        if (projectDis > setting.maxProjectDis)
            return;

        //Debug.Log("当前投射点跟上一个点的距离：" + Vector3.Distance(m_CurrentPoint, projectPoint));
        if (Vector3.Distance(m_CurrentPoint, projectPoint) > setting.newPointMaxDis)    //当前投射点跟上一个点的距离
            return;

        float nextPointDistance = Vector3.Distance(projectPoint, endPoint);
        //Debug.Log("投射点跟下个点的距离：" + nextPointDistance);
        if (nextPointDistance < 3)
        {
            m_CurrentPoint = endPoint;
            m_CurrentPointSign.position = m_CurrentPoint;
            m_WayPointIndex++;
            return;
        }

        if (Vector3.Distance(projectPoint, startPoint) > moveDirection.magnitude + 5)
            return;

        if (Vector3.Distance(projectPoint, startPoint) < Vector3.Distance(m_CurrentPoint, startPoint))
            return;

        m_CurrentPoint = projectPoint;
        m_CurrentPointSign.position = m_CurrentPoint;
    }

    void CheckDrawMask()
    {
        if (!bIsDrawing) return;

        if (bIsFirstCreateMask)
        {
            float dis1 = Vector3.Distance(m_Brush.position, m_MaskPreviousPoint);
            if (dis1 > 1)
            {
                bIsFirstCreateMask = false;
                CreateMask();
            }
        }

        float dis = Vector3.Distance(m_Brush.position, m_MaskPreviousPoint);
        if (dis > setting.drawMaskDis)
        {
            CreateMask();
            m_MaskPreviousPoint = m_Brush.position;
        }
    }

    void CreateMask()
    {
        Transform go = GameObject.Instantiate(m_DrawMask);
        go.SetParent(m_Number);
        go.gameObject.SetActive(true);
        go.position = m_Brush.Find("BrushImage").position;
        go.localScale = Vector3.one;
        m_DrawList.Add(go.gameObject);
    }


    private void SetDrawMaterial(Transform target)
    {
        if (m_NumberMaterial == null)
        {
            m_NumberMaterial = new Material(Shader.Find(downShader));
        }
        target.GetComponent<Image>().material = m_NumberMaterial;
    }

    private void SetDefaultMaterial(Transform target)
    {
        target.GetComponent<Image>().material = null;
    }

    private void SetUpMaterial(Transform target)
    {
        Image image = target.GetComponent<Image>();
        image.material.shader = Shader.Find(upShader);
    }

    private float GetPathDistance(Vector3[] paths)
    {
        float dis = 0;
        for (int i = 1; i < paths.Length; i++)
        {
            float addDis = Vector3.Distance(paths[i - 1], paths[i]);
            dis += addDis;
        }
        return dis;
    }

    protected override void OnDestroy()
    {
        Clear();
        base.OnDestroy();
    }

    private void Clear()
    {
        foreach (GameObject go in m_MaskList)
        {
            if (go != null)
                GameObject.Destroy(go);
        }
        foreach (GameObject go in m_DrawList)
        {
            if (go != null)
                GameObject.Destroy(go);
        }
        //foreach (GameObject go in m_EatAnims)
        //{
        //    if (go != null)
        //        GameObject.Destroy(go);
        //}

        //m_EatAnims.Clear();
        m_MaskList.Clear();
        m_DrawList.Clear();
        drawPathDict.Clear();
        if (m_Brush != null)
        {
            m_Brush.gameObject.SetActive(false);
        }
        if (m_Sign != null)
            m_Sign.gameObject.SetActive(false);
        if (m_CurrentPointSign != null)
        {
            Destroy(m_CurrentPointSign.gameObject);
        }
        m_CurrentPointSign = null;
        m_NumberMaterial = null;
    }


}
